package com.piper.long_connection.pb_model.core.codc;

import com.piper.long_connection.pb_model.core.model.Request;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * 数据包解码器
 * <pre>
 * 数据包格式
 * +——----——+——-----——+——----——+——----——+——-----——+——-----——+
 * |  包头	|  模块号   |  命令号    |   长度     |   数据     |
 * +——----——+——-----——+——----——+——----——+——-----——+——-----——+
 * </pre>
 * 包头4字节
 * 模块号2字节
 * 命令号2字节
 * 长度4字节(数据部分占有字节数量)
 */
public class RequestDecoder extends ByteToMessageDecoder {

    /**
     * 数据包基本长度
     */
    public static int BASE_LENTH = 4 + 2 + 2 + 4;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        // 1 字节流开始位置
        int packStartIndex;
        while (true) {

            // 获取字节流开始位置
            packStartIndex = in.readerIndex();

            // 若读取到分割标识，说明读取当前字节流开始位置了
            if (in.readInt() == ConstantValue.HEADER_FLAG) {
                break;
            }

            // 重置读索引为0
            in.resetReaderIndex();

            // 长度校验，字节流长度小于 BASE_LENTH 则等待下一次字节流过来
            if (in.readableBytes() < BASE_LENTH) {
                return;
            }
        }

        // 2 读取模块号
        short module = in.readShort();
        // 3 读取命令号
        short cmd = in.readShort();

        // 4 读取数据长度
        int length = in.readInt();

        // 校验数据包是否全部发送过来，总字节流长度（此处读取的是除去基本长度的总长度）
        if (in.readableBytes() < length) {
            // 长度校验，字节流长度少于data数据包长度，说明数据包还没到齐，等待下一次字节流过来
            in.readerIndex(packStartIndex);
            return;
        }

        // 5 数据包内容
        byte[] data = null;
        if (length > 0) {
            data = new byte[length];
            in.readBytes(data);
        }

        Request message = new Request();
        message.setModule(module);
        message.setCmd(cmd);
        message.setData(data);
        out.add(message);

        // 回收已读字节
        in.discardReadBytes();
    }

}
